/*
Level.cpp
储存游戏关卡信息，并处理传入事件
*/

#include <crossguid/guid.hpp>
#include <Level.h>
#include <Player.h>
#include <LevelAction.h>
#include <unordered_map>
#include <mutex>
#include <queue>

/*
修改后的所有标准报文
echo(e)
server_name(sn) -> name
server_info(si) -> info
server_setting
game_status(gs)
boardcast(b) -> log, content
player_action(pla) -> uuid, type, (pos, angle)(pa), hitPoints(h), score(s),
    recovery(r), fillWeapon(f), weapon.target(w.t), kdCount(kd), immuneTime(i)
projectile_action(pja) -> uuid, (pos, velocity)
youkai_action(ya) -> uuid, (pos velocity friction)
item_action(ia) -> uuid, (pos velocity)
create_player(cp) -> uuid, playerName, posX, posY
create_bullet(cb) -> uuid, bulletType, posX, posY, velocityX, velocityY, ownerUuid
create_youkai(cy) -> uuid, youkaiType, posX, posY, velocityX, velocityY, friction
create_item(ci) -> uuid, posX, posY, velocityX, velocityY
del_player(dp) -> uuid
del_bullet(db) -> uuid
del_youkai(dy) -> uuid
del_item(di) -> uuid
particle_burst(pb) -> uuid, burstName, extArgus
*/

/*
TODO：

缩减消息报头，轻量化发送数据；[v]

仅在玩家状态改变时发送消息，降低网络带宽；
    （注：因为玩家朝向也要同步，在这个案例中不大现实）[x]

为客户端添加平滑插值算法，使得网络延迟不会过于明显[v]

*/

using namespace std;

extern int gameTick;

void Level::resetAllPlayers(queue<LevelAction> &responseBuffer) {
    // 游戏开始时，重置所有玩家的状态
    for (pair<string, Player> currPlayer : players) {
        Player* targetPlayer = &players[currPlayer.second.uuid];
        targetPlayer->requireSync = true;
        targetPlayer->pos = Vector2 {(float)(rand() % 100), (float)(rand() % 100)};
        targetPlayer->velocity = Vector2 { 0, 0 };
        targetPlayer->grazeColdDown = 0.0f;
        targetPlayer->hitPoints = 100.0f;
        targetPlayer->recovery = 0.0f;
        targetPlayer->score = 0;
        targetPlayer->weapon.fillWeapon("normal_bullet", targetPlayer, responseBuffer);
        targetPlayer->killCount = 0;
        targetPlayer->deathCount = 0;
        targetPlayer->immuneTime = 3.0f;
    }
}

void Level::resetLevelStatus(queue<LevelAction> &responseBuffer) {
    youkaiDeployColdDown = 3.0f;
    for (pair<string, Youkai> youkai : youkais) {
        youkais[youkai.second.uuid].lifeTime = -1.0f;
    }
    for (pair<string, Projectile> projectile : projectiles) {
        projectiles[projectile.second.uuid].lifeTime = -1.0f;
    }
    for (pair<string, Item> item : items) {
        items[item.second.uuid].lifeTime = -1.0f;
    }
}

/// @brief 更新关卡
/// @param rate 更新速率（1/频率）
void Level::update(const float rate, mutex& mtxLock, queue<LevelAction>& responseBuffer) {
    mtxLock.lock();
    updateGameStatus(rate, responseBuffer);
    updateGameAutoStart(rate, responseBuffer);
    for (pair<string, Player> currPlayer : players) {
        Player* targetPlayer = &players[currPlayer.second.uuid];
        if (targetPlayer->requireSync) {
            syncGlobalData(responseBuffer);
            targetPlayer->requireSync = false;
        }
        // 如果要求玩家信息同步，则广播玩家创建数据
        targetPlayer->Update(rate, responseBuffer);
        updatePlayerLimit(targetPlayer, rate, responseBuffer);
        updatePlayerOpenFire(targetPlayer, rate, responseBuffer);
        // 更新玩家本体
    }
    for (pair<string, Youkai> currYoukai : youkais) {
        Youkai* targetYoukai = &youkais[currYoukai.second.uuid];
        if (targetYoukai->requireSync) {
            syncYoukaiData(targetYoukai, responseBuffer);
            targetYoukai->requireSync = false;
        }
        // 当妖怪被创建时，同步其数据给所有玩家
        targetYoukai->Update(rate, responseBuffer);
        // 更新妖怪本体
        upadteYoukaiAction(targetYoukai, rate, responseBuffer);
        // 赋予妖怪简单的AI
    }
    updateYoukaiDeploy(rate, responseBuffer);
    delDeadYoukai(responseBuffer);
    for (pair<string, Projectile> projectile : projectiles) {
        Projectile* targetBullet = &projectiles[projectile.second.uuid];
        if (targetBullet->requireSync) {
            syncProjectileData(targetBullet, responseBuffer);
            targetBullet->requireSync = false;
        }
        // 如果弹幕要求信息同步，那么就同步信息
        targetBullet->Update(rate, responseBuffer);
        updateProjectileSpecial(targetBullet, rate, responseBuffer);
        if (targetBullet->bulletType != "murasa_anchor")
            updateProjectileDamage(targetBullet, rate, responseBuffer);
        // 更新弹幕本体
    }
    delDeadProjectile(responseBuffer);
    for (pair<string, Item> item : items) {
        Item* targetItem = &items[item.second.uuid];
        if (targetItem->requireSync) {
            syncItemData(targetItem, responseBuffer);
            targetItem->requireSync = false;
        }
        // 如果道具要求信息同步，那么就同步信息
        targetItem->Update(rate, responseBuffer);
        updateItemCollection(targetItem, rate, responseBuffer);
        // 更新弹幕本体
    }
    delDeadItem(responseBuffer);
    gameTick++;
    echoResponse(responseBuffer);
    mtxLock.unlock();
}

void Level::echoResponse(queue<LevelAction> &responseBuffer) {
    while (!echo.empty()) {
        pushToResponseBuffer("e", vector<string> { echo.front() }, responseBuffer);
        echo.pop();
    }
}

void Level::updateGameAutoStart(const float rate, queue<LevelAction> &responseBuffer) {
    if (autoStart && !gameStarted && players.size() >= autoStartMinPlayerCount) {
        currStartCountDown -= rate;
        if (currStartCountDown < __FLT_EPSILON__) {
            // 时间到了，开游戏
            gameStarted = true;
            leftTime = roundTime;
            printf("Game auto started! The match would last for %f second(s)\n", leftTime);
            resetAllPlayers(responseBuffer);
            resetLevelStatus(responseBuffer);
            syncGlobalData(responseBuffer);
            sendGameLog("Game auto started.", responseBuffer);
        }
    }
    else {
        currStartCountDown = autoStartTime;
    }
}

void Level::updateGameStatus(const float rate, queue<LevelAction> &responseBuffer) {
    bool gameEndEvent = false;
    if (gameStarted) {
        leftTime = (leftTime < rate) ? 0.0f : (leftTime - rate);
        if (leftTime < __FLT_EPSILON__) {
            printf("Game ended!\n");
            resetLevelStatus(responseBuffer);
            gameStarted = false;
            gameEndEvent = true;
            currStartCountDown = autoStartTime;
            sendGameLog("Game ended.", responseBuffer);
            // 处理关卡结束事件
        }
    }
    if (gameTick % 60 == 0 || gameEndEvent) {
        vector<string> gameStatusInfo { (gameStarted ? "true" : "false"),
            to_string(leftTime), to_string(mapWidth), to_string(mapHeight),
            (autoStart ? "true" : "false"), to_string(currStartCountDown),
            to_string(autoStartMinPlayerCount) };
        pushToResponseBuffer("gs", gameStatusInfo, responseBuffer);
    }
}

void Level::updatePlayerLimit(Player* targetPlayer, const float rate, queue<LevelAction> &responseBuffer) {
    // 限制玩家的位置
    if (abs(targetPlayer->pos.x) > abs(mapWidth / 2)) {
        targetPlayer->pos.x = mapWidth / 2 * (targetPlayer->pos.x > 0 ? 1 : -1);
    }
    if (abs(targetPlayer->pos.y) > abs(mapHeight / 2)) {
        targetPlayer->pos.y = mapHeight / 2 * (targetPlayer->pos.y > 0 ? 1 : -1);
    }
}

void Level::updatePlayerOpenFire(Player* targetPlayer, const float rate, queue<LevelAction>& responseBuffer) {
    const float PI = 3.1415926f;
    targetPlayer->weapon.coldDown = ((targetPlayer->weapon.coldDown > rate) ?
    (targetPlayer->weapon.coldDown - rate) : 0.0f);
    // 满足开火条件即开火
    if (targetPlayer->mouseLeftPressed && targetPlayer->weapon.coldDown < __FLT_EPSILON__
        && targetPlayer->weapon.ammo > 0 && targetPlayer->hitPoints >= __FLT_EPSILON__
        && gameStarted && targetPlayer->immuneTime < __FLT_EPSILON__) {
        targetPlayer->weapon.coldDown = targetPlayer->weapon.maxColdDown;
        targetPlayer->weapon.ammo--;
        vector<string> weaponInfo { targetPlayer->uuid, "w.a",
            to_string(targetPlayer->weapon.ammo) };
        pushToResponseBuffer("pla", weaponInfo, responseBuffer);
        // 在这里开火（根据不同的弹幕类型决定）
        // 对于特殊弹幕类型定义特殊的开火方式
        if (targetPlayer->weapon.bulletType == "doremy_catcher") {
            float initAngle = targetPlayer->angle;
            for (int i = 0; i < 12; i++) {
                Player dummy = *targetPlayer;
                float currAngle = PI / 6.0f * i + initAngle;
                const float fireDist = 30.0f;
                Vector2 posOffset = Vector2 { fireDist * cos(currAngle), fireDist * sin(currAngle) };
                dummy.pos = targetPlayer->pos; dummy.pos.add(posOffset);
                dummy.weapon.fillWeapon("doremy_catcher", &dummy);
                Vector2 aimOffset = Vector2 { cos(currAngle + PI / 2), sin(currAngle + PI / 2) };
                dummy.mousePos = dummy.pos; dummy.mousePos.add(aimOffset);
                linearFire(&dummy, responseBuffer);
            }
        }
        if (targetPlayer->weapon.bulletType == "okina_star") {
            float initAngle = targetPlayer->angle;
            for (int i = 0; i < 7; i++) {
                Player dummy = *targetPlayer;
                float currAngle = 2 * PI * i / 7 + initAngle;
                const float fireDist = 85.0f;
                Vector2 posOffset = Vector2 { fireDist * cos(currAngle), fireDist * sin(currAngle) };
                dummy.pos = targetPlayer->pos; dummy.pos.add(posOffset);
                dummy.weapon.fillWeapon("okina_star", &dummy);
                Vector2 aimOffset = Vector2 { cos(initAngle), sin(initAngle) };
                dummy.mousePos = dummy.pos; dummy.mousePos.add(aimOffset);
                linearFire(&dummy, responseBuffer);
            }
        }
        if (targetPlayer->weapon.bulletType == "yachie_shield") {
            float initAngle = targetPlayer->angle;
            for (int i = 0; i < 3; i++) {
                Player dummy = *targetPlayer;
                float currAngle = 2 * PI * i / 3 + initAngle;
                dummy.pos = targetPlayer->pos;
                dummy.weapon.fillWeapon("yachie_shield", &dummy);
                Vector2 aimOffset = Vector2 { cos(currAngle), sin(currAngle) };
                dummy.mousePos = dummy.pos; dummy.mousePos.add(aimOffset);
                linearFire(&dummy, responseBuffer);
            }
        }
        if (targetPlayer->weapon.bulletType == "zanmu_ghost") {
            float initAngle = targetPlayer->angle;
            float swiftAngle = (float)(gameTick % 60) / 60.0f * 2 * PI;
            Player dummy = *targetPlayer;
            float currAngle = initAngle + swiftAngle;
            dummy.weapon.fillWeapon("zanmu_ghost", &dummy);
            Vector2 aimOffset = Vector2 { cos(currAngle), sin(currAngle) };
            dummy.mousePos = dummy.pos; dummy.mousePos.add(aimOffset);
            linearFire(&dummy, responseBuffer);
        }
        else {
            linearFire(targetPlayer, responseBuffer);
        }
        // 发送弹幕创建请求
    }
    if (targetPlayer->weapon.ammo == 0 && targetPlayer->weapon.coldDown < __FLT_EPSILON__) {
        targetPlayer->weapon.bulletType = "normal_bullet";
        targetPlayer->weapon.fillWeapon("normal_bullet", targetPlayer, responseBuffer);
    }
    // 更新武器，并判断是否开火
}

void Level::randomTurn(string bulletUuid, float turnRange) {
    projectiles[bulletUuid].velocity.turn((float)(rand() % 1000) /
        1000.0f * turnRange * (rand() & 1 ? -1 : 1));
    // 随机偏转弹幕
}

void Level::linearFire(Player* targetPlayer, queue<LevelAction>& responseBuffer) {
    const float PI = 3.1415926f;
    extern unordered_map<string, ProjectileData> bulletDatas;
    // 根据弹幕类型创建弹幕
    for (int i = 1; i <= bulletDatas[targetPlayer->weapon.bulletType].count; i++) {
        string bulletGuid = xg::newGuid().str();
        createNewProjectile(targetPlayer->weapon.bulletType, bulletGuid,
            targetPlayer->pos, targetPlayer->uuid, responseBuffer);
        Projectile* currBullet = &projectiles[bulletGuid];
        float randomspreadRange = bulletDatas[currBullet->bulletType].randomspreadRange;
        float velocityDecreasePerBullet = bulletDatas[currBullet->bulletType].velocityDecreasePerBullet;
        float offsetX = (float)rand() / RAND_MAX * randomspreadRange * (rand() & 1 ? -1 : 1);
        float offsetY = (float)rand() / RAND_MAX * randomspreadRange * (rand() & 1 ? -1 : 1);
        currBullet->pos = Vector2 { currBullet->pos.x + offsetX,
            currBullet->pos.y + offsetY };
        currBullet->setVelocity(Vector2 { targetPlayer->mousePos.x - currBullet->pos.x,
            targetPlayer->mousePos.y - currBullet->pos.y },
            bulletDatas[currBullet->bulletType].primarySpeed - (i - 1) * velocityDecreasePerBullet);
        randomTurn(bulletGuid, bulletDatas[currBullet->bulletType].randomspreadAngle);
        if (currBullet->bulletType == "seija_arrow") {
            currBullet->velocity.mult(-1);
        }
    }
}

Player* Level::findNearestPlayer(string bulletUuid) {
    Projectile* target = &projectiles[bulletUuid];
    Player* playerTarget = nullptr; float playerDist = __FLT_MAX__;
    for (pair<string, Player> currPlayer : players) {
        Player* currPlayerPtr = &players[currPlayer.second.uuid];
        if (currPlayerPtr->pos.distance(target->pos) < playerDist &&
        target->ownerUuid != currPlayerPtr->uuid) {
            playerDist = currPlayerPtr->pos.distance(target->pos);
            playerTarget = currPlayerPtr;
        }
    }
    return playerTarget;
}

Youkai* Level::findNearestYoukai(string bulletUuid) {
    Projectile* target = &projectiles[bulletUuid];
    Youkai* youkaiTarget = nullptr; float youkaiDist = __FLT_MAX__;
    for (pair<string, Youkai> currYoukai : youkais) {
        Youkai* currYoukaiPtr = &youkais[currYoukai.second.uuid];
        if (currYoukaiPtr->pos.distance(target->pos) < youkaiDist &&
        target->ownerUuid != currYoukaiPtr->uuid) {
            youkaiDist = currYoukaiPtr->pos.distance(target->pos);
            youkaiTarget = currYoukaiPtr;
        }
    }
    return youkaiTarget;
}

void Level::guidance(string bulletUuid, const float rate, float turnVelocity) {
    // 指挥弹幕制导攻击最近的敌对单位
    const float PI = 3.1415926f;
    Projectile* target = &projectiles[bulletUuid];
    float currAngle = vectorToAngle(target->velocity.x, target->velocity.y);
    Player* playerTarget = findNearestPlayer(bulletUuid);
    float playerDist = playerTarget == nullptr ? __FLT_MAX__ : playerTarget->pos.distance(target->pos);
    Youkai* youkaiTarget = findNearestYoukai(bulletUuid);
    float youkaiDist = youkaiTarget == nullptr ? __FLT_MAX__ : youkaiTarget->pos.distance(target->pos);
    // 找到最近的单位
    if (playerTarget != nullptr || youkaiTarget != nullptr) {
        if (playerDist < youkaiDist) {
            // 转向最近的玩家
            float distAngle = vectorToAngle(playerTarget->pos.x - target->pos.x,
                playerTarget->pos.y - target->pos.y);
            if (((distAngle - currAngle < 0) ? (distAngle - currAngle + PI * 2.0f) : (distAngle - currAngle)) <
            ((currAngle - distAngle < 0) ? (currAngle - distAngle + PI * 2.0f) : (currAngle - distAngle))) {
                target->velocity.turn(turnVelocity * rate); // 顺时针旋转
            }
            else {
                target->velocity.turn(-turnVelocity * rate); // 逆时针旋转
            }
        }
        else {
            // 转向最近的妖怪
            float distAngle = vectorToAngle(youkaiTarget->pos.x - target->pos.x,
                youkaiTarget->pos.y - target->pos.y);
            if (((distAngle - currAngle < 0) ? (distAngle - currAngle + PI * 2.0f) : (distAngle - currAngle)) <
            ((currAngle - distAngle < 0) ? (currAngle - distAngle + PI * 2.0f) : (currAngle - distAngle))) {
                target->velocity.turn(turnVelocity * rate); // 顺时针旋转
            }
            else {
                target->velocity.turn(-turnVelocity * rate); // 逆时针旋转
            }
        }
    }
}

void Level::summonSubProjectile(string bulletUuid, const float rate,
queue<LevelAction>& responseBuffer) {
    // 指挥弹幕生成字弹幕攻击对手
    if (gameTick % 25 == 0) {
        Projectile* target = &projectiles[bulletUuid];
        float currAngle = vectorToAngle(target->velocity.x, target->velocity.y);
        Player* playerTarget = findNearestPlayer(bulletUuid);
        float playerDist = playerTarget == nullptr ? __FLT_MAX__ : playerTarget->pos.distance(target->pos);
        Youkai* youkaiTarget = findNearestYoukai(bulletUuid);
        float youkaiDist = youkaiTarget == nullptr ? __FLT_MAX__ : youkaiTarget->pos.distance(target->pos);
        // 找到最近的单位
        if (playerTarget != nullptr || youkaiTarget != nullptr) {
            string bulletGuid = xg::newGuid().str();
            createNewProjectile("normal_bullet", bulletGuid,
                target->pos, target->ownerUuid, responseBuffer);
            if (playerDist < youkaiDist) {
                // 攻击最近的玩家
                projectiles[bulletGuid].setVelocity(Vector2 { playerTarget->pos.x - projectiles[bulletGuid].pos.x,
                    playerTarget->pos.y - projectiles[bulletGuid].pos.y });
            }
            else {
                // 攻击最近的妖怪
                projectiles[bulletGuid].setVelocity(Vector2 { youkaiTarget->pos.x - projectiles[bulletGuid].pos.x,
                    youkaiTarget->pos.y - projectiles[bulletGuid].pos.y });
            }
        }
    }
}

void Level::updateProjectileSpecial(Projectile* targetBullet, const float rate, queue<LevelAction> &responseBuffer) {
    const float PI = 3.1415926f;
    extern unordered_map<string, ProjectileData> bulletDatas;
    float velocityChange = bulletDatas[targetBullet->bulletType].velocityChangePerSecond;
    // 更新特殊弹幕行为
    if (abs(velocityChange) >= __FLT_EPSILON__) {
        targetBullet->setVelocity(targetBullet->velocity,
            targetBullet->velocity.returnLength() + velocityChange * rate);
    }
    if (targetBullet->bulletType == "reimu_spellcard") {
        guidance(targetBullet->uuid, rate, PI / 4.0f);
    }
    if (targetBullet->bulletType == "reimilia_arrow") {
        guidance(targetBullet->uuid, rate, PI / 8.0f);
    }
    if (targetBullet->bulletType == "doremy_catcher") {
        guidance(targetBullet->uuid, rate, PI / 6.0f);
    }
    if (targetBullet->bulletType == "zanmu_ghost") {
        guidance(targetBullet->uuid, rate, PI / 12.0f);
    }
    if (targetBullet->bulletType == "alice_doll") {
        summonSubProjectile(targetBullet->uuid, rate, responseBuffer);
    }
    if (targetBullet->bulletType == "keine_mirror" && targetBullet->lifeTime <= rate * 2.0f) {
        Player dummy = players[targetBullet->ownerUuid];
        dummy.pos = targetBullet->pos;
        dummy.weapon.fillWeapon("keine_mirror_sub", &dummy);
        linearFire(&dummy, responseBuffer);
        targetBullet->lifeTime = -1.0f;
    }
    if (targetBullet->bulletType == "yachie_shield" && targetBullet->lifeTime <= rate * 2.0f) {
        float initAngle = vectorToAngle(targetBullet->velocity.x, targetBullet->velocity.y);
        for (int i = 0; i < 3; i++) {
            Player dummy = players[targetBullet->ownerUuid];
            float currAngle = 2 * PI * i / 3 + initAngle;
            dummy.pos = targetBullet->pos;
            dummy.weapon.fillWeapon("yachie_shield_sub", &dummy);
            Vector2 aimOffset = Vector2 { cos(currAngle), sin(currAngle) };
            dummy.mousePos = dummy.pos; dummy.mousePos.add(aimOffset);
            linearFire(&dummy, responseBuffer);
        }
        targetBullet->lifeTime = -1.0f;
    }
    if (targetBullet->bulletType == "murasa_anchor") {
        Player dummy = players[targetBullet->ownerUuid];
        if (gameTick % 20 == 0) {
            dummy.pos = targetBullet->pos;
            dummy.weapon.fillWeapon("murasa_anchor_sub", &dummy);
            dummy.mousePos = dummy.pos;
            dummy.mousePos.sub(targetBullet->velocity);
            linearFire(&dummy, responseBuffer);
        }
        if (players[targetBullet->ownerUuid].mousePos.distance(targetBullet->pos) > 10.0f &&
        targetBullet->lifeTime > rate * 2.0f) {
            Vector2 direction = players[targetBullet->ownerUuid].mousePos;
            direction.sub(targetBullet->pos);
            targetBullet->setVelocity(direction, targetBullet->velocity.returnLength());
        }
        else {
            targetBullet->lifeTime = -1.0f;
            for (int i = 0; i < 24; i++) {
                string uuid = xg::newGuid().str();
                createNewProjectile("murasa_anchor_sub", uuid, targetBullet->pos, targetBullet->ownerUuid, responseBuffer);
                Vector2 aimDirection = Vector2 { cos(i * PI / 12.0f), sin(i * PI / 12.0f) };
                projectiles[uuid].setVelocity(aimDirection);
            }
        }
    }
}

void Level::updateProjectileDamage(Projectile* targetBullet, const float rate, queue<LevelAction> &responseBuffer) {
    // 对角色伤害判定
    for (pair<string, Player> currPlayer : players) {
        Player* targetPlayer = &players[currPlayer.second.uuid];
        // 玩家进入弹幕的伤害半径
        if (targetPlayer->pos.distance(targetBullet->pos) < targetBullet->hitRange
        && targetBullet->lifeTime > 0.0f && targetBullet->ownerUuid != targetPlayer->uuid
        && targetPlayer->hitPoints >= __FLT_EPSILON__ && targetPlayer->immuneTime < __FLT_EPSILON__) {
            targetBullet->lifeTime = -1.0f; // 将targetBullet生命周期归零
            targetPlayer->hitPoints -= targetBullet->hitPoints;
            vector<string> playerInfo { targetPlayer->uuid, "h",
                to_string(targetPlayer->hitPoints) };
            pushToResponseBuffer("pla", playerInfo, responseBuffer);
            // 弹幕发射者加分
            if (players.find(targetBullet->ownerUuid) != players.end()) {
                Player* damageDealer = &(players[targetBullet->ownerUuid]);
                int currPlayerScore = damageDealer->score +
                    (int)((float)targetBullet->hitPoints * damageScoreRatio);
                vector<string> burstInfo { targetPlayer->uuid, "hit_burst" };
                pushToResponseBuffer("pb", burstInfo, responseBuffer);
                if (targetPlayer->hitPoints < __FLT_EPSILON__) {
                    currPlayerScore += playerKnockDownScore;
                    vector<string> burstInfo { targetPlayer->uuid, "damage_burst" };
                    pushToResponseBuffer("pb", burstInfo, responseBuffer);
                    damageDealer->killCount += 1;
                    targetPlayer->deathCount += 1;
                    vector<string> kdInfoDealer { damageDealer->uuid, "kd",
                        to_string(damageDealer->killCount), to_string(damageDealer->deathCount) };
                    pushToResponseBuffer("pla", kdInfoDealer, responseBuffer);
                    vector<string> kdInfoTarget { targetPlayer->uuid, "kd",
                        to_string(targetPlayer->killCount), to_string(targetPlayer->deathCount) };
                    pushToResponseBuffer("pla", kdInfoTarget, responseBuffer);
                    targetPlayer->weapon.fillWeapon("normal_bullet", targetPlayer, responseBuffer);
                    sendGameLog(damageDealer->playerName + " knocked " + targetPlayer->playerName + " down.", responseBuffer);
                    vector<string> targetScoreInfo { targetPlayer->uuid, "s", to_string(targetPlayer->score),
                        "Knock Down by " + damageDealer->playerName };
                    pushToResponseBuffer("pla", targetScoreInfo, responseBuffer);
                }
                // 击杀额外加分，并统计击杀与死亡数，被击杀者丢失武器
                damageDealer->score = currPlayerScore;
                vector<string> scoreInfo { targetBullet->ownerUuid, "s", to_string(currPlayerScore),
                (targetPlayer->hitPoints < __FLT_EPSILON__ ? ("Knock Down " + targetPlayer->playerName) : "Deal Damage") };
                pushToResponseBuffer("pla", scoreInfo, responseBuffer);
            }
            else {
                // 看看能不能找到该弹幕是玩家发射的，如果不是，就是其它妖怪发射的
                // 因此被击杀的玩家扣分
                vector<string> burstInfo { targetPlayer->uuid, "hit_burst" };
                pushToResponseBuffer("pb", burstInfo, responseBuffer);
                if (targetPlayer->hitPoints < __FLT_EPSILON__) {
                    targetPlayer->deathCount += 1;
                    vector<string> kdInfoTarget { targetPlayer->uuid, "kd",
                        to_string(targetPlayer->killCount), to_string(targetPlayer->deathCount) };
                    pushToResponseBuffer("pla", kdInfoTarget, responseBuffer);
                    int currPlayerScore = targetPlayer->score - youkaiMissPenalize;
                    vector<string> burstInfo { targetPlayer->uuid, "damage_burst" };
                    pushToResponseBuffer("pb", burstInfo, responseBuffer);
                    vector<string> scoreInfo { targetPlayer->uuid, "s", to_string(currPlayerScore),
                    "Knock Down by Youkai" };
                    pushToResponseBuffer("pla", scoreInfo, responseBuffer);
                    targetPlayer->weapon.fillWeapon("normal_bullet", targetPlayer, responseBuffer);
                    sendGameLog(targetPlayer->playerName + " was knocked down by youkai.", responseBuffer);
                    targetPlayer->score = currPlayerScore;
                }
            }
        }
    }
    // 对妖怪伤害判定
    for (pair<string, Youkai> currYoukai : youkais) {
        Youkai* targetYoukai = &youkais[currYoukai.second.uuid];
        // 妖怪进入弹幕的伤害半径
        if (targetYoukai->pos.distance(targetBullet->pos) < targetBullet->hitRange
        && targetBullet->lifeTime > 0.0f && targetBullet->ownerUuid != targetYoukai->uuid
        && targetYoukai->hitPoints >= __FLT_EPSILON__) {
            // 仅当弹幕发射者是玩家才造成伤害并加分
            if (players.find(targetBullet->ownerUuid) != players.end()) {
                targetBullet->lifeTime = -1.0f; // 将targetBullet生命周期归零
                targetYoukai->hitPoints -= targetBullet->hitPoints;
                // 不发送妖怪生命值报文
                Player* damageDealer = &(players[targetBullet->ownerUuid]);
                int currPlayerScore = damageDealer->score + targetBullet->hitPoints * damageScoreRatio;
                vector<string> burstInfo { targetYoukai->uuid, "hit_burst" };
                pushToResponseBuffer("pb", burstInfo, responseBuffer);
                if (targetYoukai->hitPoints < __FLT_EPSILON__) {
                    currPlayerScore += youkaiKnockDownScore;
                } // 击杀额外加分
                damageDealer->score = currPlayerScore;
                vector<string> scoreInfo { targetBullet->ownerUuid, "s", to_string(currPlayerScore),
                (targetYoukai->hitPoints < __FLT_EPSILON__ ? "Knock Down Youkai" : "Deal Damage") };
                pushToResponseBuffer("pla", scoreInfo, responseBuffer);
            }
        }
    }
}

void Level::updateItemCollection(Item* targetItem, const float rate, queue<LevelAction> &responseBuffer) {
    // 对角色伤害判定
    for (pair<string, Player> currPlayer : players) {
        Player* targetPlayer = &players[currPlayer.second.uuid];
        // 玩家进入收集半径
        if (targetItem->pos.distance(targetPlayer->pos) < targetItem->receiveRange
        && targetItem->lifeTime > 0.0f
        && targetPlayer->hitPoints >= __FLT_EPSILON__) {
            targetItem->lifeTime = -1.0f;
            vector<string> burstInfo { targetPlayer->uuid, "graze_burst" };
            pushToResponseBuffer("pb", burstInfo, responseBuffer);
            // 粒子效果
            targetPlayer->randomWeapon(responseBuffer);
            // 随机发枪（
        }
    }
}

void Level::upadteYoukaiAction(Youkai* targetYoukai, const float rate, queue<LevelAction> &responseBuffer) {
    const float PI = 3.1415926f;
    if (targetYoukai->youkaiType == "weak_fairy") {
        Player* aimTarget = getNearestPlayer(targetYoukai, players);
        targetYoukai->mousePos = aimTarget == nullptr ? Vector2 { 0, 0 } : aimTarget->pos;
        if (targetYoukai->fireColdDown < __FLT_EPSILON__) {
            targetYoukai->fireColdDown = targetYoukai->fireMaxColdDown;
            youkaiOpenFire(targetYoukai, responseBuffer);
        }
    }
    else if (targetYoukai->youkaiType == "mult_fairy") {
        Player* aimTarget = getNearestPlayer(targetYoukai, players);
        targetYoukai->mousePos = aimTarget == nullptr ? Vector2 { 0, 0 } : aimTarget->pos;
        float aimAngle = vectorToAngle(targetYoukai->mousePos.x - targetYoukai->pos.x,
        targetYoukai->mousePos.y - targetYoukai->pos.y);
        if (targetYoukai->fireColdDown < __FLT_EPSILON__) {
            targetYoukai->fireColdDown = targetYoukai->fireMaxColdDown;
            for (int i = -2; i <= 2; i++) {
                youkaiOpenAngleFire(targetYoukai, aimAngle + i * PI / 12.0f, responseBuffer, -1);
            }
        }
    }
    else if (targetYoukai->youkaiType == "spread_fairy") {
        if (targetYoukai->fireColdDown < __FLT_EPSILON__) {
            targetYoukai->fireColdDown = targetYoukai->fireMaxColdDown;
            for (int i = 0; i < 24; i++) {
                youkaiOpenAngleFire(targetYoukai, i * PI / 12.0f, responseBuffer, -1);
            }
        }
    }
    else if (targetYoukai->youkaiType == "spread_fairy_2") {
        int quickIndex = rand() % 24;
        float primarySpeed = 320.0f;
        if (targetYoukai->fireColdDown < __FLT_EPSILON__) {
            targetYoukai->fireColdDown = targetYoukai->fireMaxColdDown;
            for (int i = 0; i < 24; i++) {
                int indexDist = min(((i - quickIndex < 0) ? (i - quickIndex + 24) : (i - quickIndex)),
                ((quickIndex - i < 0) ? (quickIndex - i + 24) : (quickIndex - i)));
                float speed = primarySpeed * (1 - (float)indexDist / 18);
                youkaiOpenAngleFire(targetYoukai, i * PI / 12.0f, responseBuffer, speed);
            }
        }
    }
}

void Level::youkaiOpenFire(Youkai* targetYoukai, queue<LevelAction> &responseBuffer) {
    string bulletUuid = xg::newGuid().str();
    createNewProjectile("normal_bullet", bulletUuid,
        targetYoukai->pos, targetYoukai->uuid, responseBuffer);
    projectiles[bulletUuid].setVelocity(Vector2 { targetYoukai->mousePos.x - targetYoukai->pos.x,
        targetYoukai->mousePos.y - targetYoukai->pos.y });
}

void Level::youkaiOpenAngleFire(Youkai* targetYoukai, float angle, queue<LevelAction> &responseBuffer, float speed) {
    string bulletUuid = xg::newGuid().str();
    createNewProjectile("normal_bullet", bulletUuid,
        targetYoukai->pos, targetYoukai->uuid, responseBuffer);
    Vector2 aimDirection = Vector2 { cos(angle), sin(angle) };
    if (speed < 0) {
        projectiles[bulletUuid].setVelocity(aimDirection);
    }
    else {
        projectiles[bulletUuid].setVelocity(aimDirection, speed);
    }
}

void Level::updateYoukaiDeploy(const float rate, queue<LevelAction> &responseBuffer) {
    if (!gameStarted) { return; }
    youkaiDeployColdDown -= rate;
    if (youkaiDeployColdDown < __FLT_EPSILON__) {
        youkaiDeployColdDown = youkaiDeployColdDownMax;
        // 部署妖怪到战场
        srand((unsigned int)time(NULL));
        int deployType = rand() % 7;
        if (deployType == 0) {
            for (int i = 1; i <= 6; i++) {
                string youkaiUuid = xg::newGuid().str();
                createNewYoukai("weak_fairy", youkaiUuid,
                    Vector2 { mapWidth / 2 * (i <= 3 ? -1 : 1) ,
                    mapHeight / 4 * ((i - 1) % 3 - 1) }, responseBuffer);
                youkais[youkaiUuid].velocity =
                    Vector2 {mapWidth / youkais[youkaiUuid].lifeTime * (i <= 3 ? 1 : -1), 0};
            }
        }
        else if (deployType == 1) {
            for (int i = 1; i <= 4; i++) {
                string youkaiUuid = xg::newGuid().str();
                createNewYoukai("mult_fairy", youkaiUuid,
                    Vector2 { mapWidth / 3 * (i <= 2 ? 1 : -1) ,
                    mapHeight / 2 * ((i - 1) & 1 ? -1 : 1) }, responseBuffer);
                youkais[youkaiUuid].velocity =
                    Vector2 {0, mapHeight / youkais[youkaiUuid].lifeTime * ((i - 1) & 1 ? 1 : -1)};
            }
        }
        else if (deployType == 2) {
            for (int i = 1; i <= 2; i++) {
                string youkaiUuid = xg::newGuid().str();
                createNewYoukai("spread_fairy", youkaiUuid,
                    Vector2 { mapWidth / 2 * (i == 1 ? -1 : 1) ,
                    mapHeight / 6 * (i == 1 ? 1 : -1) }, responseBuffer);
                youkais[youkaiUuid].velocity =
                    Vector2 {mapWidth / youkais[youkaiUuid].lifeTime * (i == 1 ? 1 : -1), 0};
            }
        }
        else if (deployType == 3) {
            for (int i = 1; i <= 2; i++) {
                string youkaiUuid = xg::newGuid().str();
                createNewYoukai("spread_fairy_2", youkaiUuid,
                    Vector2 { 0, mapHeight / 2 * (i == 1 ? -1 : 1) }, responseBuffer);
                youkais[youkaiUuid].velocity =
                    Vector2 {0, mapHeight / youkais[youkaiUuid].lifeTime * (i == 1 ? 1 : -1)};
            }
        }
        else if (deployType == 4) {
            for (int i = 1; i <= 6; i++) {
                string youkaiUuid = xg::newGuid().str();
                createNewYoukai("weak_fairy", youkaiUuid,
                    Vector2 { mapWidth / 2 * (i <= 3 ? -1 : 1) ,
                    (float)rand() / RAND_MAX * mapHeight / 2 * (rand() & 1 ? 1 : -1) }, responseBuffer);
                youkais[youkaiUuid].velocity =
                    Vector2 {mapWidth / 2 * (i <= 3 ? 1 : -1), 0};
                youkais[youkaiUuid].friction = mapWidth / 2;
            }
        }
        else if (deployType >= 5 && deployType <= 6) {
            float posY = (float)rand() / RAND_MAX * mapHeight / 2 * (rand() & 1 ? 1 : -1);
            float posX = (float)rand() / RAND_MAX * mapWidth / 2 * (rand() & 1 ? 1 : -1);
            int swapFlag = (deployType == 6) ? 1 : -1;
            for (int i = 1; i <= 5; i++) {
                string youkaiUuid = xg::newGuid().str();
                createNewYoukai("weak_fairy", youkaiUuid,
                    Vector2 { (mapWidth / 2 + 30 * i) * swapFlag , posY }, responseBuffer);
                youkais[youkaiUuid].velocity =
                    Vector2 { -(mapWidth + 150) * swapFlag / youkais[youkaiUuid].lifeTime, 0 };
            }
            for (int i = 1; i <= 5; i++) {
                string youkaiUuid = xg::newGuid().str();
                createNewYoukai("weak_fairy", youkaiUuid,
                    Vector2 { posX , -(mapHeight / 2 - 30 * i) * swapFlag }, responseBuffer);
                youkais[youkaiUuid].velocity =
                    Vector2 { 0, (mapHeight + 150) * swapFlag / youkais[youkaiUuid].lifeTime };
            }
        }
    }
}

Vector2 Level::spawnRandomDirection() {
    float moveAngle = (float)(rand() % 1000) / 1000.0f * 3.1415926f * 2.0f;
    Vector2 moveDirection { cos(moveAngle), sin(moveAngle) };
    return moveDirection;
}

void Level::createNewPlayer(const LevelAction &interact) {
    Vector2 playerPos {stof(interact.paramsList[2]), stof(interact.paramsList[3])};
    Player newPlayer;
    newPlayer.fillPlayer(interact.paramsList[1], interact.paramsList[0],
        playerPos, Weapon());
    newPlayer.requireSync = true;
    players.insert(pair<string, Player>(newPlayer.uuid, newPlayer));
    // 在服务器上创建玩家
}

void Level::createNewYoukai(string youkaiType, string uuid, Vector2 pos,
    queue<LevelAction>& responseBuffer) {
    Youkai newYoukai;
    newYoukai.fillYoukai(youkaiType, uuid, pos);
    newYoukai.requireSync = true;
    youkais.insert(pair<string, Youkai>(newYoukai.uuid, newYoukai));
    // 在服务器上创建NPC，这一步交给同步来做
}

void Level::createNewProjectile(string bulletType, string uuid, Vector2 pos, string ownerUuid,
    queue<LevelAction>& responseBuffer) {
    Projectile newProjectile;
    newProjectile.fillBullet(bulletType, uuid, pos, ownerUuid);
    newProjectile.requireSync = true;
    projectiles.insert(pair<string, Projectile>(newProjectile.uuid, newProjectile));
    // 在服务器上创建弹幕，同步交给服务器
}

void Level::createNewItem(string uuid, Vector2 pos, queue<LevelAction>& responseBuffer) {
    Item newItem;
    newItem.fillItem(uuid, pos);
    newItem.requireSync = true;
    items.insert(pair<string, Item>(newItem.uuid, newItem));
    // 并给道具赋予速度
    items[uuid].setVelocity();
}

void Level::delDeadProjectile(queue<LevelAction> &responseBuffer) {
    vector<string> delUuid;
    for (pair<string, Projectile> projectile : projectiles) {
        if (projectile.second.lifeTime < 0.0f) {
            string uuid = projectile.second.uuid;
            delUuid.push_back(uuid);
        }
    }
    for (string delTarget : delUuid) {
        projectiles.erase(delTarget);
        pushToResponseBuffer("db", vector<string> { delTarget }, responseBuffer);
    }
}

void Level::delDeadYoukai(queue<LevelAction> &responseBuffer) {
    vector<string> delUuid;
    for (pair<string, Youkai> youkai : youkais) {
        if (youkai.second.hitPoints < __FLT_EPSILON__ || youkai.second.lifeTime < 0.0f) {
            string uuid = youkai.second.uuid;
            delUuid.push_back(uuid);
        }
    }
    for (string delTarget : delUuid) {
        bool isKilled = youkais[delTarget].hitPoints < __FLT_EPSILON__;
        Vector2 delPos = youkais[delTarget].pos;
        youkais.erase(delTarget);
        if (isKilled) {
            vector<string> burstInfo { delTarget, "damage_burst" };
            pushToResponseBuffer("pb", burstInfo, responseBuffer);
            // 概率判断是否掉落道具
            if ((float)rand() / RAND_MAX <= itemDropPercentage) {
                string itemUuid = xg::newGuid().str();
                createNewItem(itemUuid, delPos, responseBuffer);
            }
        }
        pushToResponseBuffer("dy", vector<string> { delTarget }, responseBuffer);
    }
}

void Level::delDeadItem(queue<LevelAction> &responseBuffer) {
    vector<string> delUuid;
    for (pair<string, Item> item : items) {
        if (item.second.lifeTime < 0.0f) {
            string uuid = item.second.uuid;
            delUuid.push_back(uuid);
        }
    }
    for (string delTarget : delUuid) {
        items.erase(delTarget);
        pushToResponseBuffer("di", vector<string> { delTarget }, responseBuffer);
    }
}

void Level::syncGlobalData(queue<LevelAction>& responseBuffer) {
    for (pair<string, Player> currPlayer : players) {
        Player targetPlayer = currPlayer.second;
        vector<string> playerInfo { targetPlayer.uuid, targetPlayer.playerName,
            to_string(targetPlayer.velocity.x), to_string(targetPlayer.velocity.y) };
        pushToResponseBuffer("cp", playerInfo, responseBuffer);
        vector<string> hitPointsInfo { targetPlayer.uuid, "h",
            to_string(targetPlayer.hitPoints) };
        pushToResponseBuffer("pla", hitPointsInfo, responseBuffer);
        // 基本位置信息
        vector<string> weaponInfo { targetPlayer.uuid, "f", targetPlayer.weapon.bulletType,
            to_string(targetPlayer.weapon.ammo), to_string(targetPlayer.weapon.maxAmmo) };
        pushToResponseBuffer("pla", weaponInfo, responseBuffer);
        // 武器信息
        vector<string> scoreInfo { targetPlayer.uuid, "s",
            to_string(targetPlayer.score), "Level Reset" };
        pushToResponseBuffer("pla", scoreInfo, responseBuffer);
        // KD信息
        vector<string> kdInfo { targetPlayer.uuid, "kd",
            to_string(targetPlayer.killCount), to_string(targetPlayer.deathCount) };
        pushToResponseBuffer("pla", kdInfo, responseBuffer);
        // 免疫时间信息
        vector<string> immuneTimeInfo { targetPlayer.uuid, "i",
            to_string(targetPlayer.immuneTime) };
        pushToResponseBuffer("pla", immuneTimeInfo, responseBuffer);
        players[targetPlayer.uuid].requireSync = false;
    }
    for (pair<string, Projectile> currProjectile : projectiles) {
        syncProjectileData(&currProjectile.second, responseBuffer);
    }
    for (pair<string, Youkai> currYoukai : youkais) {
        syncYoukaiData(&currYoukai.second, responseBuffer);
    }
    pushToResponseBuffer("sn", vector<string> { serverName }, responseBuffer);
    pushToResponseBuffer("si", serverInfo, responseBuffer);
    printf("Data global sync done.\n");
}

void Level::syncYoukaiData(Youkai* youkai, queue<LevelAction>& responseBuffer) {
    vector<string> youkaiInfo { youkai->uuid, youkai->youkaiType,
        to_string(youkai->pos.x), to_string(youkai->pos.y),
        to_string(youkai->velocity.x), to_string(youkai->velocity.y), to_string(youkai->friction) };
    pushToResponseBuffer("cy", youkaiInfo, responseBuffer);
}

void Level::syncProjectileData(Projectile* projectile, queue<LevelAction> &responseBuffer) {
    vector<string> bulletInfo { projectile->uuid, projectile->bulletType,
        to_string(projectile->pos.x), to_string(projectile->pos.y),
        to_string(projectile->velocity.x), to_string(projectile->velocity.y), projectile->ownerUuid };
    pushToResponseBuffer("cb", bulletInfo, responseBuffer);
}

void Level::syncItemData(Item* item, queue<LevelAction> &responseBuffer) {
    vector<string> itemInfo { item->uuid, to_string(item->pos.x), to_string(item->pos.y),
        to_string(item->velocity.x), to_string(item->velocity.y) };
    pushToResponseBuffer("ci", itemInfo, responseBuffer);
}

float vectorToAngle(float x, float y) {
    float angle = atan2(y, x);
    if (angle < 0) { angle += 2 * M_PI; }
    return angle;
}

void pushToResponseBuffer(string actionName, vector<string> paramsList,
queue<LevelAction>& responseBuffer) {
    auto now = chrono::system_clock::now();
    time_t now_c = chrono::system_clock::to_time_t(now);
    auto start = chrono::system_clock::from_time_t(time_t(0));
    auto duration = now - start;
    long long unixTimeStamp = chrono::duration_cast<chrono::milliseconds>(duration).count();
    // 获取时间戳（毫秒级）
    LevelAction currAction { actionName, paramsList, unixTimeStamp };
    responseBuffer.push(currAction);
}

void sendGameLog(string content, queue<LevelAction>& responseBuffer) {
    time_t timep; time(&timep);
    auto currTime = localtime(&timep);
    string timeInfo = "[" + to_string(currTime->tm_hour) + ":" +
        to_string(currTime->tm_min) + ":" + to_string(currTime->tm_sec) + "]";
    pushToResponseBuffer("b", vector<string> { "log", timeInfo + content }, responseBuffer);
    printf("[Boardcast]%s\n", (timeInfo + content).c_str());
}